package br.gfca.simplenet.test.chat.control;

import br.gfca.simplenet.ServerImpl;
import br.gfca.simplenet.ServerListener;
import br.gfca.simplenet.WaitingFailureEvent;
import br.gfca.simplenet.test.chat.MessageHeaders;
import br.gfca.simplenet.test.chat.ui.UserEntry;
import br.gfca.simplenet.util.Printer;

public class ServerChatController implements ServerListener {
	
	private ServerImpl netController;
	private String[] nicks;
	private ServerUiIf ui;
	
	public ServerChatController(int port, int roomSize, ServerUiIf ui) {
		this.ui = ui;
		this.netController = new ServerImpl(port, roomSize, this);
		this.nicks = new String[roomSize];
	}
	
	@Override
	public void clientConnected(int newClientId) {
		this.ui.inform("Slot " + newClientId + " connected. Waiting nick.");
		
		String control = "";
		String names = "";
		String nick;
		int pos = 0;
		for (int i = 0; i < this.nicks.length; i++) {
			if ( (nick = this.nicks[i]) != null ) {
				control += "$" + pos + "_" + (pos + nick.length()) + "_" + i;
				pos += nick.length();
				names += nick; 
			}
		}
		if ( !names.equals("") ) {
			String message = control.substring(1) + "#" + names;
			this.netController.sendMessage(MessageHeaders.CONTROL_UNICAST_INFORM_USERS + message, newClientId);
		}		
	}

	@Override
	public void clientDisconnected(int leavingClientId) {
		this.ui.removeClient( new UserEntry(leavingClientId, "") );
		this.ui.inform("Slot " + leavingClientId + " disconnected: " + this.nicks[leavingClientId]);
		this.nicks[ leavingClientId ] = null;
		
		if ( !this.netController.isAccepting() ) {
			this.netController.waitConnections();
			this.ui.inform("Restarting to wait connections.");
		}
		
		this.netController.broadcastMessage( MessageHeaders.CONTROL_BROADCAST_USER_DISCONNECTED + leavingClientId, leavingClientId );
	}
	
	@Override
	public void waitingFailed( WaitingFailureEvent wfe ) {
		this.ui.waitingFailed( wfe.getMessage() );
	}

	@Override
	public void messageReceived(String message, int senderId) {
		if ( message.startsWith( MessageHeaders.MESSAGE_UNICAST ) ) {
			message = this.removeHeader(message, MessageHeaders.MESSAGE_UNICAST);
			this.ui.addChat( message );
			this.netController.broadcastMessage( MessageHeaders.MESSAGE_BROADCAST + message, senderId);
		}
		else if ( message.startsWith( MessageHeaders.CONTROL_UNICAST_INFORM_NICK )) {
			message = this.removeHeader(message, MessageHeaders.CONTROL_UNICAST_INFORM_NICK);
			this.nicks[senderId] = message;
			this.ui.newUser( new UserEntry(senderId, message) );
			this.ui.inform("Slot " + senderId + " name resolved: " + message);
			this.netController.broadcastMessage( MessageHeaders.CONTROL_BROADCAST_NEW_USER + senderId + "_" + message, senderId);
		}
		else {
			// Should never get here
			Printer.getInstance().printError("Invalid/unexpected message received: " + message);
		}
	}

	@Override
	public void messageSent(int sentToId, String message ) {		
//		if ( message.startsWith( MessageHeaders.MESSAGE_BROADCAST ) ) {
//			// nothing to do
//		}
//		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_USER_DISCONNECTED )) {
//			// nothing to do
//		}
//		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_USER_KICKED )) {
//			// nothing to do
//		}
//		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_NEW_USER )) {
//			// nothing to do
//		}
//		else if ( message.startsWith( MessageHeaders.CONTROL_UNICAST_INFORM_USERS )) {
//			// nothing to do
//		}
//		else {
//			// Should never get here
//			Printer.getInstance().printError("Invalid/unexpected message sent: " + message);
//		}
	}
	
	@Override
	public void messageFailed(int sentToId, String message) {
		if ( message.startsWith( MessageHeaders.MESSAGE_BROADCAST ) ) {
			this.netController.sendMessage(message, sentToId);
		}
		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_USER_DISCONNECTED )) {
			this.netController.sendMessage(message, sentToId);
		}
		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_USER_KICKED )) {
			this.netController.sendMessage(message, sentToId);
		}
		else if ( message.startsWith( MessageHeaders.CONTROL_BROADCAST_NEW_USER )) {
			this.netController.sendMessage(message, sentToId);
		}
		else if ( message.startsWith( MessageHeaders.CONTROL_UNICAST_INFORM_USERS )) {
			this.netController.sendMessage(message, sentToId);
		}
		else {
			// Should never get here
			Printer.getInstance().printError("Invalid/unexpected message sent, but failed: " + message);
		}		
	}
	
	@Override
	public void maxClientsReached( int maxNumber ) {
		this.ui.inform("Server is full!");
	}

	public void waitConnections() {
		this.netController.waitConnections();
		this.ui.inform("Server started. Waiting connections.");
	}

	public void stop() {
		this.netController.closeServer();
	}

	public void kickClient(int id) {
		this.netController.disconnectClient( id );
		
		this.ui.removeClient( new UserEntry(id, "") );
		this.ui.inform("Slot " + id + " disconnected: " + this.nicks[id] + " (kicked)");
		this.nicks[ id ] = null;
		
		if ( !this.netController.isAccepting() ) {
			this.netController.waitConnections();
			this.ui.inform("Restarting to wait connections.");
		}
		
		this.netController.broadcastMessage( MessageHeaders.CONTROL_BROADCAST_USER_KICKED + id, id );
	}

	private String removeHeader(String message, String messageHeader) {
		return message.substring( messageHeader.length() );
	}
}